package com.xp.basic.heima.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;


/****
 * 客户端连接服务端后，服务端发送长字符串给客户端
 */
public class TestLongTextWriteNio {

    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);
        ssc.bind(new InetSocketAddress(8080));

        ssc.register(selector, SelectionKey.OP_ACCEPT);

        while (true){
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();
                //千万忘了处理这个哦 selectionKeys 是不会删除事件的，所以处理了 事件之后要删除掉这个
                iterator.remove();
                if (selectionKey.isAcceptable()) {
                    SocketChannel sc = ssc.accept();
                    System.out.println(" client connected : "+ sc);
                    sc.configureBlocking(false);
                    SelectionKey scKey = sc.register(selector, SelectionKey.OP_READ);

                    StringBuffer buffer = new StringBuffer();
                    for (int i = 0; i < 3000000; i++) {
                        buffer.append("a");
                    }
                    ByteBuffer byteBuffer = Charset.defaultCharset().encode(buffer.toString());
                    /*while (byteBuffer.hasRemaining()) {
                        //最开始尝试在这里写，除了第一次写进去了，后面都是 0 那是因为客户端没有从缓冲区获取数据所以有问题
                        int write = sc.write(byteBuffer);
                        //再这边写了之后  需要再客户端把消息读取了 ，不然这里再次 write 是为 0 的
                        System.out.println("write = " + write);
                    }*/

                    //使用非阻塞可写事件
                    int write = sc.write(byteBuffer);
                    System.out.println("write = " + write);
                    //如果第一次没有写完，那么就注册一个可写事件
                    if (byteBuffer.hasRemaining()) {
                        scKey.interestOps(scKey.interestOps() | SelectionKey.OP_WRITE);
                        //将 buffer 作为附件添加到 key 中
                        scKey.attach(byteBuffer);
                        //这种方式不行，不能重新注册 会报错  java.lang.IllegalArgumentException
//                        sc.register(selector,sc.validOps() + SelectionKey.OP_WRITE);
                    }

                } else if (selectionKey.isReadable()) {
                    SocketChannel sc = (SocketChannel) selectionKey.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(16);
                    sc.read(buffer);
                    System.out.println("buffer.position() = " + buffer.position());
                } else if (selectionKey.isWritable()) {
                    SocketChannel sc = (SocketChannel) selectionKey.channel();
                    ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();
                    int write = sc.write(buffer);
                    System.out.println("write = " + write);
                    if (!buffer.hasRemaining()) {
                        selectionKey.interestOps(selectionKey.interestOps() ^ SelectionKey.OP_WRITE);
                        selectionKey.attach(null);
                    }
                }
            }
        }
    }
}
